package com.niknik.deberc.core;

import com.niknik.woody.core.room.Game;
import com.niknik.woody.core.room.GameEx;
import com.niknik.woody.utils.cards.Card;
import com.niknik.woody.utils.cards.CardSuit;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;

/**
 * User: yoda
 * Date: 30.01.11
 * Time: 4:22
 */
@SuppressWarnings({"unchecked"})
public class DebGame
    extends Game {

  private int _masterIdx;
  private String[] _players = new String[2];
  private List[] _plCards = {new LinkedList<Card>(), new LinkedList<Card>()};
  private int _dealer;
  private int _phase;
  private List<Card> _deck;
  private int _whichTurn;
  private Card _upCard;
  private CardSuit _kozir;
  private int _gamer;
  private Card _card1;
  private Card _card2;
  private CardComparator _cardComparator;
  private HashMap<String, LinkedList<Integer>> _playersPoints = new HashMap<String, LinkedList<Integer>>();

  public DebGame() {
    this._phase = 0;
    this._players[0] = "0";
    this._players[1] = "0";
    _masterIdx = -1;
  }

  public String getCommonState() {
    switch (this._phase) {
      case 0:
        return "0;" + this._players[0] + ',' + this._players[1] + ';' + _masterIdx;
    }
    return null;
  }

  @Override
  public void move(String playerId, String move)
      throws GameEx {
    int res = 0;
    int roundPoints = 0;
    switch (move.charAt(0)) {
      case 'j':
        if (_phase != 0) {
          //throw new GameEx("Извините, игра уже началась. Вы не можете присоединиться.", GameExceptionType.FATAL);
        }
        if ((_players[0].equals(playerId)) || (_players[1].equals(playerId))) {
          //throw new GameEx("Извините, вы уже заняли место за столом.", GameExceptionType.FATAL);
        }
        if ((!_players[0].equals("0")) && (!_players[1].equals("0"))) {
          //throw new GameEx("Извините, свободных мест в игре нет.", GameExceptionType.FATAL);
        }
        if (_players[0].equals("0")) {
          this._players[0] = playerId;
          this._playersPoints.put(playerId, new LinkedList<Integer>());
          //this._sessions[0] = session;
          if (_masterIdx == -1) {
            _masterIdx = 0;
          }
        }
        else {
          this._players[1] = playerId;
          this._playersPoints.put(playerId, new LinkedList<Integer>());
          //this._sessions[1] = session;
          if (_masterIdx == -1) {
            _masterIdx = 1;
          }
        }

        publishToAll("0;" + this._players[0] + ',' + this._players[1] + ';' + _masterIdx);
        break;
      case 'l':
        int place;
        if (_players[0].equals(playerId)) {
          place = 0;
        }
        else if (_players[1].equals(playerId)) {
          place = 1;
        }
        else {
          place = -1;
        }
        if (place == -1) {
          //throw new GameEx("Извините, вы не сидите за столом.", GameExceptionType.FATAL);
        }
        switch (_phase) {
          case 0:
            this._players[place] = "0";
            //                  this._sessions[place] = null;

            int firstNotEmpty;
            if (!_players[0].equals("0")) {
              firstNotEmpty = 0;
            }
            else if (!_players[1].equals("0")) {
              firstNotEmpty = 1;
            }
            else {
              firstNotEmpty = -1;
            }

            if (firstNotEmpty == -1) {
              this._phase = 51;
              this._masterIdx = -1;
              //deleteMe();
            }
            else {
              if (this._masterIdx == place) {
                this._masterIdx = firstNotEmpty;
              }
              publishToAll(this.getCommonState());
            }

            break;
          case 1:
          case 2:
          case 3:
          case 4:
            this._phase = 52;

            publishToAll("52;" + place);
            //deleteMe();
            break;
          case 50:
          case 51:
          case 52:
            break;
          default:
            //throw new GameEx("Недопустимое действие.", GameExceptionType.ERROR);
        }
        break;
      case 's':
        if (_phase != 0) {
          //throw new GameEx("Извините, игра уже начата.", GameExceptionType.FATAL);
        }
        if ((_players[0].equals("0")) || (_players[1].equals("0"))) {
          //throw new GameEx("Извините, но для начала игры нужно " + _players.length + " игрока.",
          //    GameExceptionType.ERROR);
        }
        if (!_players[_masterIdx].equals(playerId)) {
          //throw new GameEx("Извините, но у вас нет прав, что бы начать эту игру.", GameExceptionType.ERROR);
        }
        _phase++;
        _deck = DebercHelper.getShuffledDeck();
        for (int i = 0; i < 6; i++) {
          _plCards[0].add(_deck.remove(0));
        }
        for (int i = 0; i < 6; i++) {
          _plCards[1].add(_deck.remove(0));
        }
        _dealer = DebercHelper.RANDOM.nextInt(_players.length);
        _whichTurn = (_dealer + 1) % _players.length;
        _upCard = _deck.get(_deck.size() - 1);
        for (int i = 0; i < _players.length; i++) {
          StringBuilder sb = new StringBuilder("1;");
          sb.append(_dealer);
          sb.append(';');
          sb.append(_upCard);
          sb.append(';');
          sb.append(_plCards[i].get(0).toString());
          sb.append(',');
          sb.append(_plCards[i].get(1).toString());
          sb.append(',');
          sb.append(_plCards[i].get(2).toString());
          sb.append(',');
          sb.append(_plCards[i].get(3).toString());
          sb.append(',');
          sb.append(_plCards[i].get(4).toString());
          sb.append(',');
          sb.append(_plCards[i].get(5).toString());
          publish(sb.toString(), _players[i]);
        }
        for (String id : this._players) {
          this._playersPoints.get(id).add(0);
        }
        break;
      case 'p':
        if ((playerId.equals("0")) || ((!playerId.equals(_players[0])) && (!playerId.equals(_players[1])))) {
          //throw new GameEx("Извините, вы не играете за этим столом.", GameExceptionType.FATAL);
        }
        if (_phase != 1) {
          //throw new GameEx("Извините, вы не можете сейчас пасовать.", GameExceptionType.ERROR);
        }
        if (!playerId.equals(_players[_whichTurn])) {
          //throw new GameEx("Извините, сейчас не ваш ход.", GameExceptionType.ERROR);
        }
        if (_whichTurn == _dealer) {
          _phase = 2;
        }
        _whichTurn = (_whichTurn + 1) % _players.length;
        this.publishToAll("p");
        break;
      case 'w':
        if ((playerId.equals("0")) || ((!playerId.equals(_players[0])) && (!playerId.equals(_players[1])))) {
          //throw new GameEx("Извините, вы не играете за этим столом.", GameExceptionType.FATAL);
        }
        if (_phase != 2) {
          //throw new GameEx("Извините, вы не можете сейчас пасовать.", GameExceptionType.ERROR);
        }
        if (!playerId.equals(_players[_whichTurn])) {
          //throw new GameEx("Извините, сейчас не ваш ход.", GameExceptionType.ERROR);
        }
        if (_whichTurn == _dealer) {
          //throw new GameEx("Извините, на вас обяз.", GameExceptionType.ERROR);
        }
        _whichTurn = (_whichTurn + 1) % _players.length;
        this.publishToAll("w");
        break;
      case 'k':
        if ((playerId.equals("0")) || ((!playerId.equals(_players[0])) && (!playerId.equals(_players[1])))) {
          //throw new GameEx("Извините, вы не играете за этим столом.", GameExceptionType.FATAL);
        }
        if (_phase != 1) {
          //throw new GameEx("Извините, вы не можете сейчас оставлять козырь.", GameExceptionType.ERROR);
        }
        if (!playerId.equals(_players[_whichTurn])) {
          //throw new GameEx("Извините, сейчас не ваш ход.", GameExceptionType.ERROR);
        }
        _gamer = _whichTurn;
        _kozir = _upCard.getSuit();
        this._cardComparator = new CardComparator(_kozir);
        _phase = 3;

        for (int i = 0; i < _players.length; i++) {
          StringBuilder sb = new StringBuilder("k;");
          Card card = _deck.remove(0);
          _plCards[i].add(card);
          sb.append(card);
          sb.append(',');
          card = _deck.remove(0);
          _plCards[i].add(card);
          sb.append(card);
          sb.append(',');
          card = _deck.remove(0);
          _plCards[i].add(card);
          sb.append(card);
          publish(sb.toString(), _players[i]);
        }
        break;
      case 't':
        if ((playerId.equals("0")) || ((!playerId.equals(_players[0])) && (!playerId.equals(_players[1])))) {
          //throw new GameEx("Извините, вы не играете за этим столом.", GameExceptionType.FATAL);
        }
        if (_phase != 2) {
          //throw new GameEx("Извините, вы не можете сейчас выбирать козырь.", GameExceptionType.ERROR);
        }
        if (!playerId.equals(_players[_whichTurn])) {
          //throw new GameEx("Извините, сейчас не ваш ход.", GameExceptionType.ERROR);
        }
        CardSuit newKozir = CardSuit.fromString(move.substring(2));
        if (newKozir == _upCard.getSuit()) {
          //throw new GameEx("Извините, сейчас не можете выбирать эту масть для козыря.", GameExceptionType.ERROR);
        }

        _gamer = _whichTurn;
        _kozir = newKozir;
        _phase = 3;

        for (int i = 0; i < _players.length; i++) {
          StringBuilder sb = new StringBuilder("t;");
          Card card = _deck.remove(0);
          _plCards[i].add(card);
          sb.append(card);
          sb.append(',');
          card = _deck.remove(0);
          _plCards[i].add(card);
          sb.append(card);
          sb.append(',');
          card = _deck.remove(0);
          _plCards[i].add(card);
          sb.append(card);
          sb.append(';');
          sb.append(_kozir.toString());
          publish(sb.toString(), _players[i]);
        }
        break;
      case 'm':
        if ((playerId.equals("0")) || ((!playerId.equals(_players[0])) && (!playerId.equals(_players[1])))) {
          //throw new GameEx("Извините, вы не играете за этим столом.", GameExceptionType.FATAL);
        }
        if (!playerId.equals(_players[_whichTurn])) {
          //throw new GameEx("Извините, сейчас не ваш ход.", GameExceptionType.ERROR);
        }
        if (_phase < 3) {
          //throw new GameEx("Произошло шото не то", GameExceptionType.ERROR);
        }
        if (_phase == 3) {
          String card1Str = move.substring(2);
          for (Card card : (List<Card>) _plCards[_whichTurn]) {
            if (card.toString().equals(card1Str)) {
              this._card1 = card;
              break;
            }
          }
          _plCards[_whichTurn].remove(this._card1);// 1st made move, appropriate card removed from his deck
          _phase = 4;
        }
        else if (_phase == 4) {
          String card2Str = move.substring(2);
          for (Card card : (List<Card>) _plCards[_whichTurn]) {
            if (card.toString().equals(card2Str)) {
              this._card2 = card;
              break;
            }
          }
          System.out.println(_card1 + " vs " + _card2);
          boolean val = _cardComparator.validateMove(_card1, _card2, _plCards[_whichTurn]);
          if (!val) {
            _phase = 4;
            //throw new GameEx("Неправильный ход", GameExceptionType.ERROR);
          }
          _plCards[_whichTurn].remove(_card2);
          res = _cardComparator.compare(_card1, _card2);
          _phase = 3;
          System.out.println(playerId + (res < 0
              ? " wins "
              : " loses ") + res);
          String pointsReceiver = res < 0
              ? _players[_whichTurn]
              : _players[(_whichTurn + 1) % _players.length];
          roundPoints = _cardComparator.getCardPoints(_card1) + _cardComparator.getCardPoints(_card2);
          LinkedList<Integer> list = this._playersPoints.get(pointsReceiver);
          list.set(list.size() - 1, list.getLast() + roundPoints);
          if (_plCards[_whichTurn].isEmpty()) {
            _phase = 5;
          }
        }
        if (_phase != 5) {
          if (res < 0) {
            this.publishToAll(move + ";n" + ";" + roundPoints);//player the same (n=not changing)
            break;
          }
          _whichTurn = (_whichTurn + 1) % _players.length;
          this.publishToAll(move + ";c" + ";" + roundPoints); //player changing (c=changing)
          break;
        }
        else {
          LinkedList<Integer> gamerAllPoints = this._playersPoints.get(_players[_gamer]);
          LinkedList<Integer> opponentAllPoints = this._playersPoints.get(_players[(_gamer + 1) % _players.length]);
          int gamerPoints = gamerAllPoints.getLast();//points after ending this deal
          int opponentPoints = opponentAllPoints.getLast();
          boolean wellDeal = gamerPoints > opponentPoints;//this deal was good for 'gamer'?
          String wellDealStr = (wellDeal
              ? "sigral"
              : "ne sigral");
          if (!wellDeal) {
            gamerAllPoints.set(gamerAllPoints.size() - 1, 0);
            opponentAllPoints.set(opponentAllPoints.size() - 1, opponentPoints + gamerPoints);
          }
          this.publishToAll(move + ";f" + ";" + roundPoints + ";" + wellDealStr.charAt(0));
          System.out.println("finish! player " + _players[_gamer] + " " + wellDealStr);
          _phase = 0;
          this.move(String.valueOf(_whichTurn), "s");
        }
    }
  }

  private void publishToAll(String data) {
    for (String playerId : _players) {
      if (!playerId.equals("0")) {
        publish(data, playerId);
      }
    }
  }

}
